import numpy as np
from keras.datasets import mnist
from keras.utils import to_categorical
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Dropout, Flatten, Dense
from keras.optimizers import RMSprop
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix
import itertools
from keras.callbacks import ModelCheckpoint
import matplotlib.font_manager as fm

plt.rcParams['font.family'] = 'SimHei'

# 准备数据
(x_Train,y_Train),(x_Test,y_Test)=mnist.load_data()
x_Train=x_Train.reshape(x_Train.shape[0],28,28,1).astype('float32')/256
x_Test=x_Test.reshape(x_Test.shape[0],28,28,1).astype('float32')/256
y_Train=to_categorical(y_Train)
y_Test =to_categorical(y_Test)

# 构建神经网络模型
model =Sequential()
model.add(Conv2D(filters=16,                    #2维卷积层，16个卷积核
                kernel_size=(5,5),              #卷积核的尺寸，超参数
                padding='same',
                input_shape=(28,28,1),
                activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(filters=36,
                kernel_size=(5,5),
                padding='same',
                activation='relu'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Dropout(0.3))                        # 超参数
model.add(Flatten())                            # 展开成一维向量
model.add(Dense(128,activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10,activation='softmax'))

# 回调函数
checkpoint = ModelCheckpoint(filepath='best_model.h5', monitor='val_accuracy', verbose=1, save_best_only=True)

# 训练和评估神经网络模型
model.compile(loss='categorical_crossentropy',
              optimizer=RMSprop(lr=0.001),      # 超参数
              metrics=['accuracy'])
train_history=model.fit(x=x_Train,
                        y=y_Train,
                        validation_split=0.2,
                        epochs=15,              # 超参数
                        batch_size=300,         # 超参数
                        callbacks=[checkpoint],
                        verbose=2)

# 保存最终模型权重
model.save_weights('final_model.h5')

# 绘制训练过程中的准确率和损失值变化情况
def plot_acc_loss(train_history):
    plt.figure(figsize=(10,5))
    plt.subplot(1,2,1)
    plt.plot(train_history.history['accuracy'],color='b',label='训练')
    plt.plot(train_history.history['val_accuracy'],color='r',label='测试')
    plt.legend(loc='best')
    plt.xlabel('训练轮数')
    plt.ylabel('准确率')

    plt.subplot(1,2,2)
    plt.plot(train_history.history['loss'],color='b',label='训练')
    plt.plot(train_history.history['val_loss'],color='r',label='测试')
    plt.legend(loc='best')
    plt.xlabel('训练轮数')
    plt.ylabel('损失值')
    plt.show()

plot_acc_loss(train_history)

# 在测试集上评估模型表现
scores =model.evaluate(x_Test,y_Test,batch_size=512)
print("测试损失:", scores[0])
print("测试准确率:", scores[1])

